fix(auth): resolve CORS errors for self-hosted deployments behind reverse proxies#4369
Conversation
…erse proxies
- auth client now uses browser origin first, falling back to NEXT_PUBLIC_APP_URL
- socket client falls back to page origin when served from non-localhost (assumes /socket.io is proxied)
- add TRUSTED_ORIGINS env var to extend Better Auth trustedOrigins (apex+www, alias hostnames)
- warn at startup when NEXT_PUBLIC_APP_URL is localhost in production
- preprocess empty NEXT_PUBLIC_SOCKET_URL so docker-compose ${VAR:-} works
- migrate remaining uuid/nanoid/randomUUID usages to @sim/utils generateId/generateShortId
- extend generateShortId with optional alphabet param (rejection sampling)
- document TRUSTED_ORIGINS in .env.example, docker-compose.prod.yml, and helm values.yaml
Fixes #1243
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR SummaryMedium Risk Overview Adds Also standardizes ID generation by replacing remaining Reviewed by Cursor Bugbot for commit 7b32375. Configure here. |
Greptile SummaryThis PR fixes CORS errors for self-hosted deployments by making the auth client prefer the browser's actual origin over the build-time Confidence Score: 5/5Safe to merge — changes are well-tested, targeted at a real self-hosting pain point, and introduce no correctness regressions. Only finding is a P2 nit (dead '::1' entry in a Set that is never matched by the URL API). All core logic is correct: auth client browser-origin preference, TRUSTED_ORIGINS validation, rejection-sampling in generateShortId, and socket URL fallback. 14 new unit tests pass, Docker/Helm config changes are aligned with the new defaults. apps/sim/lib/core/utils/urls.ts (minor dead-code nit on line 106) Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[getSocketUrl called] --> B{NEXT_PUBLIC_SOCKET_URL set and non-empty?}
B -- Yes --> C[Return explicit NEXT_PUBLIC_SOCKET_URL]
B -- No --> D{Running in browser?\nwindow defined?}
D -- No SSR --> E[Return http://localhost:3002]
D -- Yes --> F{Is page origin a localhost hostname?\nlocalhost / 127.0.0.1 / ::1}
F -- Yes --> E
F -- No --> G[Return window.location.origin\ne.g. https://sim.example.com]
style C fill:#4ade80
style G fill:#4ade80
style E fill:#facc15
Reviews (6): Last reviewed commit: "chore: untrack and ignore .claude/schedu..." | Re-trigger Greptile |
|
@greptile |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 592b97c. Configure here.
…alidation is true)
Migration scripts now import generateId from @sim/utils/id; without copying packages/utils into the image, bun install fails to resolve the workspace dep at build time and the import fails at runtime.
|
@greptile |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 5420245. Configure here.
The realtime service never reads NEXT_PUBLIC_SOCKET_URL — its env schema only includes BETTER_AUTH_URL, NEXT_PUBLIC_APP_URL, ALLOWED_ORIGINS, BETTER_AUTH_SECRET, INTERNAL_API_SECRET, DATABASE_URL, and REDIS_URL. Remove the dead config from all helm values files and the values schema.
|
@greptile |
|
@cursor review |
The default in values.yaml is now "" (empty string), which falls back to the page origin at runtime. The schema previously required a valid URI, which would reject the default. Mirror the INTERNAL_API_BASE_URL pattern using anyOf with const "". Also add TRUSTED_ORIGINS to the schema.
|
@greptile |
|
@cursor review |
The page-origin fallback in getSocketUrl() means self-hosters no longer need to set NEXT_PUBLIC_SOCKET_URL when realtime is on the same origin as the app. Update docs to reflect this: - Remove NEXT_PUBLIC_SOCKET_URL from .env scaffolding examples in docker.mdx, platforms.mdx, environment-variables.mdx - Mark the variable as Optional in the env vars table with the new default behavior described - Update troubleshooting to point at reverse-proxy /socket.io routing rather than the env var - Flip dev docker-compose defaults (local, ollama, devcontainer) from http://localhost:3002 to empty for consistency with prod.yml; the in-code localhost fallback handles the dev case identically Applied across all 6 documentation languages (en/fr/de/ja/es/zh).
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit c0de38b. Configure here.
|
@greptile |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 7b32375. Configure here.
Summary
NEXT_PUBLIC_APP_URL— fixes "Failed to create account" CORS errors when self-hosters' build-time env doesn't match the public origin/socket.ioworks without settingNEXT_PUBLIC_SOCKET_URLTRUSTED_ORIGINSenv var (comma-separated) merged into Better AuthtrustedOriginsfor apex+www / alias domainsNEXT_PUBLIC_APP_URLis localhost in productionuuid/nanoid/crypto.randomUUID()usages to@sim/utilsgenerateId/generateShortId; extendgenerateShortIdwith optional alphabet parampackages/utilsin the migrations Docker image so the@sim/*workspace dep resolvesTRUSTED_ORIGINSand the new socket fallback in.env.example,docker-compose.prod.yml, andhelm/sim/values.yamlFixes #1243
Type of Change
Testing
Tested manually. Added unit tests for
getBrowserOrigin,getSocketUrlresolution order,parseOriginList, andisLocalhostUrl(14 tests). Alllib/auth+lib/core/utils/urlstests passing.Checklist